/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

//#ifdef HAVE_CONFIG_H
//#include "mediastreamer-config.h"
//#endif
//
//extern void __register_ffmpeg_encoders_if_possible(void);
//
#include "mediastreamer2/mscommon.h"
//#include "mediastreamer2/msfilter.h"

//#include "alldescs.h"
//#include "mediastreamer2/mssndcard.h"
//#include "mediastreamer2/mswebcam.h"

//#if !defined(_WIN32_WCE)
//#include <sys/types.h>
//#endif
//#ifndef WIN32
//#include <dirent.h>
//#else
//#ifndef PACKAGE_PLUGINS_DIR
//#if defined(WIN32) || defined(_WIN32_WCE)
//#define PACKAGE_PLUGINS_DIR "plugins\\"
//#else
//#define PACKAGE_PLUGINS_DIR "."
//#endif
//#endif
//#endif
//#ifdef HAVE_DLOPEN
//#include <dlfcn.h>
//#endif
//
//#if defined(__APPLE__) && !defined(__GNUC__)
//#import <Cocoa/Cocoa.h>
//#include <Foundation/Foundation.h> 
//#endif
//
//#ifdef ANDROID
//#include <android/log.h>
//#endif

MSList *ms_list_new(void *data){
	MSList *new_elem=(MSList *)ms_new(MSList,1);
	new_elem->prev=new_elem->next=NULL;
	new_elem->data=data;
	return new_elem;
}

MSList * ms_list_append(MSList *elem, void * data){
	MSList *new_elem=ms_list_new(data);
	MSList *it=elem;
	if (elem==NULL) return new_elem;
	while (it->next!=NULL) it=ms_list_next(it);
	it->next=new_elem;
	new_elem->prev=it;
	return elem;
}

MSList * ms_list_prepend(MSList *elem, void *data){
	MSList *new_elem=ms_list_new(data);
	if (elem!=NULL) {
		new_elem->next=elem;
		elem->prev=new_elem;
	}
	return new_elem;
}


MSList * ms_list_concat(MSList *first, MSList *second){
	MSList *it=first;
	if (it==NULL) return second;
	while(it->next!=NULL) it=ms_list_next(it);
	it->next=second;
	second->prev=it;
	return first;
}

MSList * ms_list_free(MSList *list){
	MSList *elem = list;
	MSList *tmp;
	if (list==NULL) return NULL;
	while(elem->next!=NULL) {
		tmp = elem;
		elem = elem->next;
		ms_free(tmp);
	}
	ms_free(elem);
	return NULL;
}

MSList * ms_list_remove(MSList *first, void *data){
	MSList *it;
	it=ms_list_find(first,data);
	if (it) return ms_list_remove_link(first,it);
	else {
		ms_warning("ms_list_remove: no element with %p data was in the list", data);
		return first;
	}
}

int ms_list_size(const MSList *first){
	int n=0;
	while(first!=NULL){
		++n;
		first=first->next;
	}
	return n;
}

void ms_list_for_each(const MSList *list, void (*func)(void *)){
	for(;list!=NULL;list=list->next){
		func(list->data);
	}
}

void ms_list_for_each2(const MSList *list, void (*func)(void *, void *), void *user_data){
	for(;list!=NULL;list=list->next){
		func(list->data,user_data);
	}
}

MSList *ms_list_remove_link(MSList *list, MSList *elem){
	MSList *ret;
	if (elem==list){
		ret=elem->next;
		elem->prev=NULL;
		elem->next=NULL;
		if (ret!=NULL) ret->prev=NULL;
		ms_free(elem);
		return ret;
	}
	elem->prev->next=elem->next;
	if (elem->next!=NULL) elem->next->prev=elem->prev;
	elem->next=NULL;
	elem->prev=NULL;
	ms_free(elem);
	return list;
}

MSList *ms_list_find(MSList *list, void *data){
	for(;list!=NULL;list=list->next){
		if (list->data==data) return list;
	}
	return NULL;
}

MSList *ms_list_find_custom(MSList *list, int (*compare_func)(const void *, const void*), void *user_data){
	for(;list!=NULL;list=list->next){
		if (compare_func(list->data,user_data)==0) return list;
	}
	return NULL;
}

void * ms_list_nth_data(const MSList *list, int index){
	int i;
	for(i=0;list!=NULL;list=list->next,++i){
		if (i==index) return list->data;
	}
	ms_error("ms_list_nth_data: no such index in list.");
	return NULL;
}

int ms_list_position(const MSList *list, MSList *elem){
	int i;
	for(i=0;list!=NULL;list=list->next,++i){
		if (elem==list) return i;
	}
	ms_error("ms_list_position: no such element in list.");
	return -1;
}

int ms_list_index(const MSList *list, void *data){
	int i;
	for(i=0;list!=NULL;list=list->next,++i){
		if (data==list->data) return i;
	}
	ms_error("ms_list_index: no such element in list.");
	return -1;
}

MSList *ms_list_insert_sorted(MSList *list, void *data, int (*compare_func)(const void *, const void*)){
	MSList *it,*previt=NULL;
	MSList *nelem;
	MSList *ret=list;
	if (list==NULL) return ms_list_append(list,data);
	else{
		nelem=ms_list_new(data);
		for(it=list;it!=NULL;it=it->next){
			previt=it;
			if (compare_func(data,it->data)<=0){
				nelem->prev=it->prev;
				nelem->next=it;
				if (it->prev!=NULL)
					it->prev->next=nelem;
				else{
					ret=nelem;
				}
				it->prev=nelem;
				return ret;
			}
		}
		previt->next=nelem;
		nelem->prev=previt;
	}
	return ret;
}

MSList *ms_list_insert(MSList *list, MSList *before, void *data){
	MSList *elem;
	if (list==NULL || before==NULL) return ms_list_append(list,data);
	for(elem=list;elem!=NULL;elem=ms_list_next(elem)){
		if (elem==before){
			if (elem->prev==NULL)
				return ms_list_prepend(list,data);
			else{
				MSList *nelem=ms_list_new(data);
				nelem->prev=elem->prev;
				nelem->next=elem;
				elem->prev->next=nelem;
				elem->prev=nelem;
			}
		}
	}
	return list;
}

MSList *ms_list_copy(const MSList *list){
	MSList *copy=NULL;
	const MSList *iter;
	for(iter=list;iter!=NULL;iter=ms_list_next(iter)){
		copy=ms_list_append(copy,iter->data);
	}
	return copy;
}


//#ifdef __APPLE__
//#define PLUGINS_EXT ".dylib"
//#else
//#define PLUGINS_EXT ".so"
//#endif
//
//typedef void (*init_func_t)(void);
//
//int ms_load_plugins(const char *dir){
//	int num=0;
//#if defined(WIN32) && !defined(_WIN32_WCE)
//	WIN32_FIND_DATA FileData; 
//	HANDLE hSearch; 
//	char szDirPath[1024]; 
//	char szPluginFile[1024]; 
//	BOOL fFinished = FALSE;
//	const char *tmp=getenv("DEBUG");
//	BOOL debug=(tmp!=NULL && atoi(tmp)==1);
//	snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
//
//	// Start searching for .dll files in the current directory.
//
//	snprintf(szDirPath, sizeof(szDirPath), "%s\\*.dll", dir);
//	hSearch = FindFirstFile(szDirPath, &FileData);
//	if (hSearch == INVALID_HANDLE_VALUE)
//	{
//		ms_message("no plugin (*.dll) found in %s.", szDirPath);
//		return 0;
//	}
//	snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
//
//	while (!fFinished) 
//	{
//		/* load library */
//		HINSTANCE os_handle;
//		UINT em;
//		if (!debug) em = SetErrorMode (SEM_FAILCRITICALERRORS);
//		
//		snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName);
//		os_handle = LoadLibraryEx (szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
//		if (os_handle==NULL)
//		{
//			ms_message("Fail to load plugin %s with altered search path: error %i",szPluginFile,GetLastError());
//			os_handle = LoadLibraryEx (szPluginFile, NULL, 0);
//		}
//		if (!debug) SetErrorMode (em);
//		if (os_handle==NULL)
//			ms_error("Fail to load plugin %s", szPluginFile); 
//		else{
//			init_func_t initroutine;
//			char szPluginName[256]; 
//			char szMethodName[256];
//			char *minus;
//			snprintf(szPluginName, 256, "%s", FileData.cFileName);
//			/*on mingw, dll names might be libsomething-3.dll. We must skip the -X.dll stuff*/
//			minus=strchr(szPluginName,'-');
//			if (minus) *minus='\0';
//			else szPluginName[strlen(szPluginName)-4]='\0'; /*remove .dll*/
//			snprintf(szMethodName, 256, "%s_init", szPluginName);
//			initroutine = (init_func_t) GetProcAddress (os_handle, szMethodName);
//				if (initroutine!=NULL){
//					initroutine();
//					ms_message("Plugin loaded (%s)", szPluginFile);
//					num++;
//				}else{
//					ms_warning("Could not locate init routine of plugin %s. Should be %s",
//					szPluginFile, szMethodName);
//				}
//		}
//		if (!FindNextFile(hSearch, &FileData)) {
//			if (GetLastError() == ERROR_NO_MORE_FILES){ 
//				fFinished = TRUE; 
//			} 
//			else 
//			{ 
//				ms_error("couldn't find next plugin dll."); 
//				fFinished = TRUE; 
//			} 
//		}
//	} 
//	/* Close the search handle. */
//	FindClose(hSearch);
//
//#elif HAVE_DLOPEN
//	DIR *ds;
//	struct dirent *de;
//	char *fullpath;
//	ds=opendir(dir);	
//	if (ds==NULL){
//		ms_message("Cannot open directory %s: %s",dir,strerror(errno));
//		return -1;
//	}
//	while( (de=readdir(ds))!=NULL){
//		if ((de->d_type==DT_REG && strstr(de->d_name,PLUGINS_EXT)!=NULL)
//		    || (de->d_type==DT_UNKNOWN && strstr(de->d_name,PLUGINS_EXT)==de->d_name+strlen(de->d_name)-strlen(PLUGINS_EXT))) {
//			void *handle;
//			fullpath=ms_strdup_printf("%s/%s",dir,de->d_name);
//			ms_message("Loading plugin %s...",fullpath);
//			
//			if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){
//				ms_warning("Fail to load plugin %s : %s",fullpath,dlerror());
//			}else {
//				char *initroutine_name=ms_malloc0(strlen(de->d_name)+10);
//				char *p;
//				void *initroutine=NULL;
//				strcpy(initroutine_name,de->d_name);
//				p=strstr(initroutine_name,PLUGINS_EXT);
//				if (p!=NULL){
//					strcpy(p,"_init");
//					initroutine=dlsym(handle,initroutine_name);
//				}
//
//#ifdef __APPLE__
//				if (initroutine==NULL){
//					/* on macosx: library name are libxxxx.1.2.3.dylib */
//					/* -> MUST remove the .1.2.3 */
//					p=strstr(initroutine_name,".");
//					if (p!=NULL)
//					{
//						strcpy(p,"_init");
//						initroutine=dlsym(handle,initroutine_name);
//					}
//				}
//#endif
//
//				if (initroutine!=NULL){
//					init_func_t func=(init_func_t)initroutine;
//					func();
//					ms_message("Plugin loaded (%s)", fullpath);
//					num++;
//				}else{
//					ms_warning("Could not locate init routine of plugin %s",de->d_name);
//				}
//				ms_free(initroutine_name);
//			}
//			ms_free(fullpath);
//		}
//	}
//	closedir(ds);
//#else
//	ms_warning("no loadable plugin support: plugins cannot be loaded.");
//	num=-1;
//#endif
//	return num;
//}
//
//
//#ifdef __ALSA_ENABLED__
//extern MSSndCardDesc alsa_card_desc;
//#endif
//
//#ifdef HAVE_SYS_SOUNDCARD_H
//extern MSSndCardDesc oss_card_desc;
//#endif
//
//#ifdef __ARTS_ENABLED__
//extern MSSndCardDesc arts_card_desc;
//#endif
//
//#ifdef WIN32
//extern MSSndCardDesc winsnd_card_desc;
//#endif
//
//#ifdef __DIRECTSOUND_ENABLED__
//extern MSSndCardDesc winsndds_card_desc;
//#endif
//
//#ifdef __MACSND_ENABLED__
//extern MSSndCardDesc ca_card_desc;
//#endif
//
//#ifdef __PORTAUDIO_ENABLED__
//extern MSSndCardDesc pasnd_card_desc;
//#endif
//
//#ifdef __MAC_AQ_ENABLED__
//extern MSSndCardDesc aq_card_desc;
//#endif
//
//#ifdef __PULSEAUDIO_ENABLED__
//extern MSSndCardDesc pulse_card_desc;
//#endif
//
//static MSSndCardDesc * ms_snd_card_descs[]={
//#ifdef __ALSA_ENABLED__
//	&alsa_card_desc,
//#endif
//#ifdef HAVE_SYS_SOUNDCARD_H
//	&oss_card_desc,
//#endif
//#ifdef __ARTS_ENABLED__
//	&arts_card_desc,
//#endif
//#ifdef WIN32
//	&winsnd_card_desc,
//#endif
//#ifdef __DIRECTSOUND_ENABLED__
//	&winsndds_card_desc,
//#endif
//#ifdef __PORTAUDIO_ENABLED__
//	&pasnd_card_desc,
//#endif
//#ifdef __MACSND_ENABLED__
//	&ca_card_desc,
//#endif
//#ifdef __MAC_AQ_ENABLED__
//	&aq_card_desc,
//#endif
//#ifdef __PULSEAUDIO_ENABLED__
//	&pulse_card_desc,
//#endif
//	NULL
//};
//
//#ifdef VIDEO_ENABLED
//
//#ifdef __linux
//extern MSWebCamDesc v4l_desc;
//#endif
//
//#ifdef HAVE_LINUX_VIDEODEV2_H
//extern MSWebCamDesc v4l2_card_desc;
//#endif
//
//#ifdef WIN32
//extern MSWebCamDesc ms_vfw_cam_desc;
//#endif
//#if defined(WIN32) && defined(HAVE_DIRECTSHOW)
//extern MSWebCamDesc ms_directx_cam_desc;
//#endif
//
//#ifdef __MINGW32__
//extern MSWebCamDesc ms_dshow_cam_desc;
//#endif
//
//#ifdef __APPLE__
//extern MSWebCamDesc ms_v4m_cam_desc;
//#endif
//
//#if !defined(NO_FFMPEG)
//extern MSWebCamDesc static_image_desc;
//extern MSWebCamDesc mire_desc;
//#endif
//
//static MSWebCamDesc * ms_web_cam_descs[]={
//#ifdef HAVE_LINUX_VIDEODEV2_H
//	&v4l2_card_desc,
//#endif
//#ifdef __linux
//	&v4l_desc,
//#endif
//#if defined(WIN32) && defined(HAVE_DIRECTSHOW)
//	&ms_directx_cam_desc,
//#endif
//#if defined(WIN32) && defined(HAVE_VFW)
//	&ms_vfw_cam_desc,
//#endif
//#ifdef __MINGW32__
//	&ms_dshow_cam_desc,
//#endif
//#ifdef __APPLE__
//	&ms_v4m_cam_desc,
//#endif
//
//#if !defined(NO_FFMPEG)
//	&mire_desc,
//	&static_image_desc,
//#endif
//	NULL
//};
//
//#endif
//
//#ifdef ANDROID
//#define LOG_DOMAIN "mediastreamer"
//static void ms_android_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
//	int prio;
//	switch(lev){
//	case ORTP_DEBUG:	prio = ANDROID_LOG_DEBUG;	break;
//	case ORTP_MESSAGE:	prio = ANDROID_LOG_INFO;	break;
//	case ORTP_WARNING:	prio = ANDROID_LOG_WARN;	break;
//	case ORTP_ERROR:	prio = ANDROID_LOG_ERROR;	break;
//	case ORTP_FATAL:	prio = ANDROID_LOG_FATAL;	break;
//	default:		prio = ANDROID_LOG_DEFAULT;	break;
//	}
//	__android_log_vprint(prio, LOG_DOMAIN, fmt, args);
//}
//#endif
//
//void ms_init(){
//	int i;
//	MSSndCardManager *cm;
//
//#if !defined(_WIN32_WCE)
//	if (getenv("MEDIASTREAMER_DEBUG")!=NULL){
//		ortp_set_log_level_mask(ORTP_DEBUG|ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
//	}
//#endif
//#ifdef ANDROID
//	ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
//	ortp_set_log_handler(ms_android_log_handler);
//#endif
//	ms_message("Registering all filters...");
//	/* register builtin MSFilter's */
//	for (i=0;ms_filter_descs[i]!=NULL;i++){
//		ms_filter_register(ms_filter_descs[i]);
//	}
//	ms_message("Registering all soundcard handlers");
//	cm=ms_snd_card_manager_get();
//	for (i=0;ms_snd_card_descs[i]!=NULL;i++){
//		ms_snd_card_manager_register_desc(cm,ms_snd_card_descs[i]);
//	}
//
//#ifdef VIDEO_ENABLED
//	ms_message("Registering all webcam handlers");
//	{
//		MSWebCamManager *wm;
//		wm=ms_web_cam_manager_get();
//		for (i=0;ms_web_cam_descs[i]!=NULL;i++){
//			ms_web_cam_manager_register_desc(wm,ms_web_cam_descs[i]);
//		}
//	}
//#if !defined(NO_FFMPEG)
//	__register_ffmpeg_encoders_if_possible();
//#endif
//#endif
//	ms_message("Loading plugins");
//	ms_load_plugins(PACKAGE_PLUGINS_DIR);
//	ms_message("ms_init() done");
//}
//
//void ms_exit(){
//	ms_filter_unregister_all();
//	ms_snd_card_manager_destroy();
//#ifdef VIDEO_ENABLED
//	ms_web_cam_manager_destroy();
//#endif
//}
//
//void ms_sleep(int seconds){
//#ifdef WIN32
//	Sleep(seconds*1000);
//#else
//	struct timespec ts,rem;
//	int err;
//	ts.tv_sec=seconds;
//	ts.tv_nsec=0;
//	do {
//		err=nanosleep(&ts,&rem);
//		ts=rem;
//	}while(err==-1 && errno==EINTR);
//#endif
//}
//
//void ms_usleep(uint64_t usec){
//#ifdef WIN32
//	Sleep((DWORD)(usec/1000));
//#else
//	struct timespec ts,rem;
//	int err;
//	ts.tv_sec=usec/1000000LL;
//	ts.tv_nsec=(usec%1000000LL)*1000;
//	do {
//		err=nanosleep(&ts,&rem);
//		ts=rem;
//	}while(err==-1 && errno==EINTR);
//#endif
//}
//
//#define DEFAULT_MAX_PAYLOAD_SIZE 1440
//
//static int max_payload_size=DEFAULT_MAX_PAYLOAD_SIZE;
//
//int ms_get_payload_max_size(){
//	return max_payload_size;
//}
//
//void ms_set_payload_max_size(int size){
//	if (size<=0) size=DEFAULT_MAX_PAYLOAD_SIZE;
//	max_payload_size=size;
//}




